Loading required package: ggplot2
Welcome! Want to learn more? See two factoextra-related books at https://goo.gl/ve3WBa
Registered S3 method overwritten by 'data.table':
  method           from
  print.data.table     
Registered S3 method overwritten by 'htmlwidgets':
  method           from         
  print.htmlwidget tools:rstudio

Attaching package: ‘plotly’

The following object is masked from ‘package:ggplot2’:

    last_plot

The following object is masked from ‘package:stats’:

    filter

The following object is masked from ‘package:graphics’:

    layout
Registered S3 methods overwritten by 'dbplyr':
  method         from
  print.tbl_lazy     
  print.tbl_sql      
── Attaching packages ─────────────────────────────────────────────────────────── tidyverse 1.3.0 ──
✓ tibble  3.1.0     ✓ dplyr   1.0.4
✓ tidyr   1.1.2     ✓ stringr 1.4.0
✓ readr   1.4.0     ✓ forcats 0.5.1
✓ purrr   0.3.4     
── Conflicts ────────────────────────────────────────────────────────────── tidyverse_conflicts() ──
x dplyr::filter() masks plotly::filter(), stats::filter()
x dplyr::lag()    masks stats::lag()

Attaching package: ‘MASS’

The following object is masked from ‘package:dplyr’:

    select

The following object is masked from ‘package:plotly’:

    select

---------------------
Welcome to dendextend version 1.14.0
Type citation('dendextend') for how to cite the package.

Type browseVignettes(package = 'dendextend') for the package vignette.
The github page is: https://github.com/talgalili/dendextend/

Suggestions and bug-reports can be submitted at: https://github.com/talgalili/dendextend/issues
Or contact: <tal.galili@gmail.com>

    To suppress this message use:  suppressPackageStartupMessages(library(dendextend))
---------------------


Attaching package: ‘dendextend’

The following object is masked from ‘package:stats’:

    cutree

Attaching package: ‘ggpubr’

The following object is masked from ‘package:dendextend’:

    rotate

To demostrate how to do the gene clustering usign COTAN we begin importing the COTAN object that stores all elaborated data and, in this case, regarding a mouse embrionic cortex dataset (developmental stage E17.5).

[1] "calculating gene coexpression space: output tanh of reduced coex matrix"
     L11      L12    L2/31    L2/32      L41      L42    L5/61    L5/62    Prog1    Prog2 
  "Reln"   "Lhx5"  "Satb2"   "Cux1"   "Rorb"   "Sox5" "Bcl11b"  "Fezf2"    "Vim"   "Hes1" 
[1] "Get p-values on a set of genes on columns genome wide on rows"
[1] "Using function S"
[1] "function to generate S "
[1] "Secondary markers:181"
[1] "function to generate S "
[1] "Columns (V set) number: 181 Rows (U set) number: 1236"

Hierarchical clustering

par_pca = pca_1[colnames(g.space)[colnames(g.space) %in% rownames(pca_1)],]
#plot N 1
p1 <- ggparagraph(text = paste0(rownames(par_pca[par_pca$hclust == par_pca["Fezf2","hclust"],]), collapse = ", "), 
                  face = "italic", 
                  size =10, 
                  color = "#3C5488FF")

#plot N 2
p2 = ggparagraph(text = paste0(rownames(par_pca[par_pca$hclust == unique(par_pca$hclust)[!unique(par_pca$hclust) %in% unique(par_pca[unlist(layers),"hclust"])][1],]), collapse = ", "), 
                 face = "italic", 
                 size =10, 
                 color = "gray")

#plot N 3
p3 = ggparagraph(text = paste0(rownames(par_pca[par_pca$hclust == unique(par_pca$hclust)[!unique(par_pca$hclust) %in% unique(par_pca[unlist(layers),"hclust"])][2],]), collapse = ", "), 
                 face = "italic", 
                 size =10, 
                 color = "gray")
#plot N 4
p4 = ggparagraph(text = paste0(rownames(par_pca[par_pca$hclust == par_pca["Reln","hclust"],]), collapse = ", "), 
                 face = "italic", 
                 size =10, 
                 color = "#E64B35FF")

#plot N 5
p5 = ggparagraph(text = paste0(rownames(par_pca[par_pca$hclust == par_pca["Cux1","hclust"],]), collapse = ", "), 
                 face = "italic", 
                 size =10, 
                 color = par_pca["Cux1","colors"])
#plot N 6
p6 = ggparagraph(text = paste0(rownames(par_pca[par_pca$hclust == par_pca["Rorb","hclust"],]), collapse = ", "), 
                 face = "italic", 
                 size =10, 
                 color = par_pca["Rorb","colors"])
#plot N 7
p7 = ggparagraph(text = paste0(rownames(par_pca[par_pca$hclust == par_pca["Vim","hclust"],]), collapse = ", "), 
                 face = "italic", 
                 size =10, 
                 color = par_pca["Vim","colors"])

w = ggparagraph(text = " ", 
                 face = "italic", 
                 size =10, 
                 color = "white")

pp =ggarrange(p3,p5,p1,p2,p4,p6,p7,w,
          ncol = 1, nrow = 8,
          heights = c(0.1,0.15,0.23, 0.1, 0.2, 0.2, 0.1, 0.35))

    
lay <- rbind(c(1,NA),
             c(1,2.5),
             c(1,2.5),
             c(1,2.5),
             c(1,2.5),
             c(1,2.5),
             c(1,NA))

gridExtra::grid.arrange(tree, pp, layout_matrix = lay)

or just with primary markers

Now we can plot the PCA

[1] 676
[1] 1046

t-SNE code and plot

# run the t-SNE
cl.genes.tsne = Rtsne(g.space ,initial_dims = 100, dims = 2, perplexity=30,eta = 200, verbose=F, max_iter = 3000,theta=0.4,num_threads = 10,pca_center = T, pca_scale = FALSE, normalize = T )

d_tsne_1 = as.data.frame(cl.genes.tsne$Y)
rownames(d_tsne_1) = rownames(g.space)

d_tsne_1 = d_tsne_1[order.dendrogram(dend),]

# save the cluster numebr inside a dataframe with the t-SNE information
d_tsne_1$hclust = cut

d_tsne_1$names = rownames(d_tsne_1)

# as before to label only some genes
textdf <- d_tsne_1[rownames(d_tsne_1) %in% c(unlist(layers),unlist(controls)),]

for (m in c(1:length(controls))) {
  for (g in controls[[m]]) {
    if(g %in% rownames(textdf)){
      textdf[g,"highlight"] = names(controls[m])
    } 
  }
}


 p1 = ggplot(subset(d_tsne_1,!hclust %in% unique(cut[unlist(layers)])), aes(x=V1, y=V2)) +  geom_point(alpha = 0.3, color = "#B09C85FF", size=1)

p2 = p1 + geom_point(data = subset(d_tsne_1, hclust %in% unique(cut[unlist(layers)]) ), aes(x=V1, y=V2, colour=as.character(hclust)),size=1,alpha = 0.5) +
    scale_color_manual("Status", values = mycolours2)  +
  scale_fill_manual("Status", values = mycolours2)  +
  xlab("") + ylab("")+
  geom_label_repel(data =textdf , aes(x = V1, y = V2, label = names,fill=as.character(hclust)),
                   label.size = NA, 
                   alpha = 0.5, 
                   direction = "both",
                   na.rm=TRUE,
                   seed = 1234) +
  geom_label_repel(data =textdf , aes(x = V1, y = V2, label = names),
                   label.size = NA, 
                   segment.color = 'black',
                   segment.size = 0.5,
                   direction = "both",
                   alpha = 1, 
                   na.rm=TRUE,
                   fill = NA,
                   seed = 1234) +
  ggtitle("t-SNE") +
  theme_light(base_size=10) +
  theme(axis.text.x=element_blank(),plot.title = element_text(size=14, 
                                    face="italic", 
                                    color="#3C5488FF",
                                    hjust=0.01,
                                    lineheight=1.2,margin = margin(t = 5, b = -15)),
        axis.text.y=element_blank(),
        legend.position = "none")  # titl)
p2

Code to create an iteractive plot. This can be modified to be used with all the plots.

Multidimensional scaling (MDS) and plot

R version 4.0.4 (2021-02-15)
Platform: x86_64-pc-linux-gnu (64-bit)
Running under: Ubuntu 18.04.5 LTS

Matrix products: default
BLAS:   /usr/lib/x86_64-linux-gnu/openblas/libblas.so.3
LAPACK: /usr/lib/x86_64-linux-gnu/libopenblasp-r0.2.20.so

locale:
 [1] LC_CTYPE=en_US.UTF-8       LC_NUMERIC=C               LC_TIME=en_US.UTF-8        LC_COLLATE=en_US.UTF-8    
 [5] LC_MONETARY=en_US.UTF-8    LC_MESSAGES=en_US.UTF-8    LC_PAPER=en_US.UTF-8       LC_NAME=C                 
 [9] LC_ADDRESS=C               LC_TELEPHONE=C             LC_MEASUREMENT=en_US.UTF-8 LC_IDENTIFICATION=C       

attached base packages:
[1] grid      stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
 [1] ggpubr_0.4.0      dendextend_1.14.0 MASS_7.3-53.1     htmlwidgets_1.5.3 forcats_0.5.1     stringr_1.4.0    
 [7] dplyr_1.0.4       purrr_0.3.4       readr_1.4.0       tidyr_1.1.2       tibble_3.0.6      tidyverse_1.3.0  
[13] plotly_4.9.3      Rtsne_0.15        ggrepel_0.9.1     COTAN_0.1.0       factoextra_1.0.7  ggplot2_3.3.3    

loaded via a namespace (and not attached):
 [1] matrixStats_0.58.0   fs_1.5.0             lubridate_1.7.9.2    filelock_1.0.2       RColorBrewer_1.1-2  
 [6] httr_1.4.2           tools_4.0.4          backports_1.2.1      R6_2.5.0             DBI_1.1.1           
[11] lazyeval_0.2.2       BiocGenerics_0.36.0  colorspace_2.0-0     GetoptLong_1.0.5     withr_2.4.1         
[16] tidyselect_1.1.0     gridExtra_2.3        curl_4.3             compiler_4.0.4       cli_2.3.0           
[21] rvest_0.3.6          Cairo_1.5-12.2       basilisk.utils_1.2.2 xml2_1.3.2           labeling_0.4.2      
[26] scales_1.1.1         rappdirs_0.3.3       digest_0.6.27        foreign_0.8-81       rmarkdown_2.7       
[31] rio_0.5.16           basilisk_1.2.1       pkgconfig_2.0.3      htmltools_0.5.1.1    dbplyr_2.1.0        
[36] rlang_0.4.10         GlobalOptions_0.1.2  readxl_1.3.1         rstudioapi_0.13      gridGraphics_0.5-1  
[41] farver_2.0.3         shape_1.4.5          generics_0.1.0       jsonlite_1.7.2       crosstalk_1.1.1     
[46] zip_2.1.1            car_3.0-10           magrittr_2.0.1       Matrix_1.3-2         Rcpp_1.0.6          
[51] munsell_0.5.0        S4Vectors_0.28.1     abind_1.4-5          reticulate_1.18      viridis_0.5.1       
[56] lifecycle_0.2.0      stringi_1.5.3        yaml_2.2.1           carData_3.0-4        parallel_4.0.4      
[61] crayon_1.4.0         lattice_0.20-41      haven_2.3.1          cowplot_1.1.1        circlize_0.4.12     
[66] hms_1.0.0            knitr_1.31           ComplexHeatmap_2.6.2 pillar_1.4.7         rjson_0.2.20        
[71] ggsignif_0.6.1       stats4_4.0.4         reprex_1.0.0         glue_1.4.2           evaluate_0.14       
[76] data.table_1.13.6    modelr_0.1.8         png_0.1-7            vctrs_0.3.6          cellranger_1.1.0    
[81] gtable_0.3.0         clue_0.3-58          assertthat_0.2.1     openxlsx_4.2.3       xfun_0.20           
[86] broom_0.7.5          rstatix_0.7.0        viridisLite_0.3.0    IRanges_2.24.1       cluster_2.1.1       
[91] ellipsis_0.3.1      
LS0tCnRpdGxlOiAiR2VuZV9jbHVzdGVyaW5nIgpvdXRwdXQ6CiAgaHRtbF9kb2N1bWVudDoKICAgIGNvbGxhcHNlZDogbm8KICAgIGNzczogaHRtbC1tZC0wMS5jc3MKICAgIGZpZ19jYXB0aW9uOiB5ZXMKICAgIGhpZ2hsaWdodDogaGFkZG9jawogICAgbnVtYmVyX3NlY3Rpb25zOiB5ZXMKICAgIHRoZW1lOiBzcGFjZWxhYgogICAgdG9jOiB5ZXMKICAgIHRvY19mbG9hdDogeWVzCiAgaHRtbF9ub3RlYm9vazoKICAgIGNvbGxhcHNlZDogbm8KICAgIGNzczogaHRtbC1tZC0wMS5jc3MKICAgIGZpZ19jYXB0aW9uOiB5ZXMKICAgIGhpZ2hsaWdodDogaGFkZG9jawogICAgbnVtYmVyX3NlY3Rpb25zOiB5ZXMKICAgIHRoZW1lOiBzcGFjZWxhYgogICAgdG9jOiB5ZXMKICAgIHRvY19mbG9hdDogeWVzCi0tLQoKYGBge3IsIGluY2x1ZGUgPSBGQUxTRX0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KAogIGNvbGxhcHNlID0gVFJVRSwKICBjb21tZW50ID0gIiM+IiwKICBmaWcud2lkdGggPSA3LAogIGZpZy5oZWlnaHQgPSA3CikKYGBgCgpgYGB7ciBzZXR1cH0KCmxpYnJhcnkoZmFjdG9leHRyYSkKbGlicmFyeShDT1RBTikKbGlicmFyeShnZ3JlcGVsKQpsaWJyYXJ5KFJ0c25lKQpsaWJyYXJ5KHBsb3RseSkKbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkoaHRtbHdpZGdldHMpCmxpYnJhcnkoTUFTUykKbGlicmFyeShkZW5kZXh0ZW5kKQpsaWJyYXJ5KGdyaWQpCmxpYnJhcnkoZ2dwdWJyKQpgYGAKClRvIGRlbW9zdHJhdGUgaG93IHRvIGRvIHRoZSBnZW5lIGNsdXN0ZXJpbmcgdXNpZ24gQ09UQU4gd2UgYmVnaW4gaW1wb3J0aW5nIHRoZSBDT1RBTiBvYmplY3QgdGhhdCBzdG9yZXMgYWxsIGVsYWJvcmF0ZWQgZGF0YSBhbmQsIGluIHRoaXMgY2FzZSwgcmVnYXJkaW5nIGEgbW91c2UgZW1icmlvbmljIGNvcnRleCBkYXRhc2V0IChkZXZlbG9wbWVudGFsIHN0YWdlIEUxNy41KS4KCmBgYHtyfQppbnB1dF9kaXIgPSAiRGF0YS8iCmxheWVycyA9IGxpc3QoIkwxIj1jKCJSZWxuIiwiTGh4NSIpLCAiTDIvMyI9YygiU2F0YjIiLCJDdXgxIiksICJMNCI9YygiUm9yYiIsIlNveDUiKSAsICJMNS82Ij1jKCJCY2wxMWIiLCJGZXpmMiIpICwgIlByb2ciPWMoIlZpbSIsIkhlczEiKSkKI29iakUxNyA9IHJlYWRSRFMoZmlsZSA9IHBhc3RlKGlucHV0X2RpciwiRTE3LjVfY29ydGV4LmNvdGFuLlJEUyIsIHNlcCA9ICIiKSkKb2JqRTE3ID0gcmVhZFJEUyhmaWxlID0gcGFzdGUoaW5wdXRfZGlyLCJFMTdfY29ydGV4X2NsMi5jb3Rhbi5SRFMiLCBzZXAgPSAiIikpCmBgYAoKYGBge3J9Cmcuc3BhY2UgPSBnZXQuZ2VuZS5jb2V4cHJlc3Npb24uc3BhY2Uob2JqRTE3LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuLmdlbmVzLmZvci5tYXJrZXIgPSAyNSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwcmltYXJ5Lm1hcmtlcnMgPSB1bmxpc3QobGF5ZXJzKSkKYGBgCmBgYHtyfQpnLnNwYWNlID0gYXMuZGF0YS5mcmFtZShhcy5tYXRyaXgoZy5zcGFjZSkpCgpjb2V4LnBjYS5nZW5lcyA8LSBwcmNvbXAodChnLnNwYWNlKSwKICAgICAgICAgICAgICAgICBjZW50ZXIgPSBUUlVFLAogICAgICAgICAgICAgICAgIHNjYWxlLiA9IEYpIAoKZnZpel9laWcoY29leC5wY2EuZ2VuZXMsIGFkZGxhYmVscz1UUlVFLG5jcCA9IDEwKQojZnZpel9laWcoY29leC5wY2EuZ2VuZXMsIGNob2ljZSA9ICJlaWdlbnZhbHVlIiwgYWRkbGFiZWxzPVRSVUUpCmBgYApIaWVyYXJjaGljYWwgY2x1c3RlcmluZwoKYGBge3IgaW5jbHVkZT1GQUxTRX0KaGMubm9ybSA9IGhjbHVzdChkaXN0KGcuc3BhY2UpLCBtZXRob2QgPSAid2FyZC5EMiIpCgpkZW5kIDwtIGFzLmRlbmRyb2dyYW0oaGMubm9ybSkKCnBjYV8xID0gYXMuZGF0YS5mcmFtZShjb2V4LnBjYS5nZW5lcyRyb3RhdGlvblssMToxMF0pCnBjYV8xID0gcGNhXzFbb3JkZXIuZGVuZHJvZ3JhbShkZW5kKSxdCgpjdXQgPSBjdXRyZWUoaGMubm9ybSwgayA9IDcsIG9yZGVyX2NsdXN0ZXJzX2FzX2RhdGEgPSBGKQoKIy0gTmV4dCBsaW5lcyBhcmUgb25seSB0byBjb2xvciBhbmQgcGxvdCB0aGUgc2Vjb25kYXJ5IG1hcmtlcnMKCnRtcCA9IGdldC5wdmFsKG9iamVjdCA9IG9iakUxNyxnZW5lLnNldC5jb2wgPXVubGlzdChsYXllcnMpLGdlbmUuc2V0LnJvdyA9IGNvbG5hbWVzKGcuc3BhY2UpKQpmb3IgKG0gaW4gdW5saXN0KGxheWVycykpIHsKICB0bXAgPSBhcy5kYXRhLmZyYW1lKHRtcFtvcmRlcih0bXBbLG1dKSxdKQogIHRtcCRyYW5rID0gYygxOm5yb3codG1wKSkKICBjb2xuYW1lcyh0bXApW25jb2wodG1wKV0gPSBwYXN0ZSgicmFuayIsbSxzZXAgPSAiLiIpCiAgfQpyYW5rLmdlbmVzID0gdG1wWywobGVuZ3RoKHVubGlzdChsYXllcnMpKSsxKTpuY29sKHRtcCldCmZvciAoYyBpbiBjKDE6bGVuZ3RoKGNvbG5hbWVzKHJhbmsuZ2VuZXMpKSkpIHsKICBjb2xuYW1lcyhyYW5rLmdlbmVzKVtjXSA9c3Ryc3BsaXQoY29sbmFtZXMocmFuay5nZW5lcylbY10sIHNwbGl0PScuJyxmaXhlZCA9IFQpW1sxXV1bMl0KfQoKTDEgPSByb3dTdW1zKHJhbmsuZ2VuZXNbLGxheWVyc1tbMV1dXSkKTDFbbGF5ZXJzW1sxXV1dID0gMQpMMiA9IHJvd1N1bXMocmFuay5nZW5lc1ssbGF5ZXJzW1syXV1dKQpMMltsYXllcnNbWzJdXV0gPSAxCkw0ID0gcm93U3VtcyhyYW5rLmdlbmVzWyxsYXllcnNbWzNdXV0pCkw0W2xheWVyc1tbM11dXSA9IDEKTDUgPXJvd1N1bXMocmFuay5nZW5lc1ssbGF5ZXJzW1s0XV1dKQpMNVtsYXllcnNbWzRdXV0gPSAxClAgPSByb3dTdW1zKHJhbmsuZ2VuZXNbLGxheWVyc1tbNV1dXSkKUFtsYXllcnNbWzVdXV0gPSAxCmNvbC5zZWNvbmRhcnkgPSBtZXJnZShMMSxMMixieT0icm93Lm5hbWVzIixhbGwueD1UUlVFKQpjb2xuYW1lcyhjb2wuc2Vjb25kYXJ5KVsyOjNdID0gYygiTDEiLCJMMiIpCnJvd25hbWVzKGNvbC5zZWNvbmRhcnkpID0gY29sLnNlY29uZGFyeSRSb3cubmFtZXMKY29sLnNlY29uZGFyeSA9IGNvbC5zZWNvbmRhcnlbLDI6bmNvbChjb2wuc2Vjb25kYXJ5KV0KY29sLnNlY29uZGFyeSA9IG1lcmdlKGNvbC5zZWNvbmRhcnksTDQsYnk9InJvdy5uYW1lcyIsYWxsLng9VFJVRSkKY29sbmFtZXMoY29sLnNlY29uZGFyeSlbbmNvbChjb2wuc2Vjb25kYXJ5KV0gPSAiTDQiCnJvd25hbWVzKGNvbC5zZWNvbmRhcnkpID0gY29sLnNlY29uZGFyeSRSb3cubmFtZXMKY29sLnNlY29uZGFyeSA9IGNvbC5zZWNvbmRhcnlbLDI6bmNvbChjb2wuc2Vjb25kYXJ5KV0KY29sLnNlY29uZGFyeSA9IG1lcmdlKGNvbC5zZWNvbmRhcnksTDUsYnk9InJvdy5uYW1lcyIsYWxsLng9VFJVRSkKY29sbmFtZXMoY29sLnNlY29uZGFyeSlbbmNvbChjb2wuc2Vjb25kYXJ5KV0gPSAiTDUiCnJvd25hbWVzKGNvbC5zZWNvbmRhcnkpID0gY29sLnNlY29uZGFyeSRSb3cubmFtZXMKY29sLnNlY29uZGFyeSA9IGNvbC5zZWNvbmRhcnlbLDI6bmNvbChjb2wuc2Vjb25kYXJ5KV0KY29sLnNlY29uZGFyeSA9IG1lcmdlKGNvbC5zZWNvbmRhcnksUCxieT0icm93Lm5hbWVzIixhbGwueD1UUlVFKQpjb2xuYW1lcyhjb2wuc2Vjb25kYXJ5KVtuY29sKGNvbC5zZWNvbmRhcnkpXSA9ICJQIgpyb3duYW1lcyhjb2wuc2Vjb25kYXJ5KSA9IGNvbC5zZWNvbmRhcnkkUm93Lm5hbWVzCmNvbC5zZWNvbmRhcnkgPSBjb2wuc2Vjb25kYXJ5WywyOm5jb2woY29sLnNlY29uZGFyeSldCgojICB0aGlzIHBhcnQgaXMgdG8gY2hlY2sgdGhhdCB3ZSB3aWxsIGNvbG9yIGFzIHNlY29uZGFyeSBtYXJrZXJzIG9ubHkgdGhlIGdlbmVzIGxpbmtlZCB0byB0aGUKIyBwcmltYXJ5IHdpdGggcG9zaXRpdmUgY29leAp0ZW1wLmNvZXggPSBhcy5tYXRyaXgob2JqRTE3QGNvZXhbcm93bmFtZXMob2JqRTE3QGNvZXgpICVpbiUgcm93bmFtZXMoY29sLnNlY29uZGFyeSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgY29sbmFtZXMob2JqRTE3QGNvZXgpICVpbiUgdW5saXN0KGxheWVycyldKQpmb3IgKG4gaW4gcm93bmFtZXMoY29sLnNlY29uZGFyeSkpIHsKICBpZihhbnkodGVtcC5jb2V4W24sYygiUmVsbiIsIkxoeDUiKV0gPCAwKSl7CiAgICBjb2wuc2Vjb25kYXJ5W24sIkwxIl0gPSAxMDAwMDAKICB9CiAgaWYoYW55KHRlbXAuY29leFtuLGMoIkN1eDEiLCJTYXRiMiIpXSA8IDApKXsKICAgIGNvbC5zZWNvbmRhcnlbbiwiTDIiXSA9IDEwMDAwMAogIH0KICBpZihhbnkodGVtcC5jb2V4W24sYygiUm9yYiIsIlNveDUiKV0gPCAwKSl7CiAgICBjb2wuc2Vjb25kYXJ5W24sIkw0Il0gPSAxMDAwMDAKICB9CiAgaWYoYW55KHRlbXAuY29leFtuLGMoIkJjbDExYiIsIkZlemYyIildIDwgMCkpewogICAgY29sLnNlY29uZGFyeVtuLCJMNSJdID0gMTAwMDAwCiAgfQogIGlmKGFueSh0ZW1wLmNvZXhbbixjKCJWaW0iLCJIZXMxIildIDwgMCkpewogICAgY29sLnNlY29uZGFyeVtuLCJQIl0gPSAxMDAwMDAKICB9Cn0KCm15bGlzdC5uYW1lcyA8LSBjKCJMMSIsICJMMiIsICJMNCIsIkw1IiwiUCIpCnBvcy5saW5rICA8LSB2ZWN0b3IoImxpc3QiLCBsZW5ndGgobXlsaXN0Lm5hbWVzKSkKbmFtZXMocG9zLmxpbmspIDwtIG15bGlzdC5uYW1lcwpmb3IgKGcgaW4gcm93bmFtZXMoY29sLnNlY29uZGFyeSkpIHsKICBpZihsZW5ndGgoIHdoaWNoKGNvbC5zZWNvbmRhcnlbZyxdID09IG1pbihjb2wuc2Vjb25kYXJ5W2csXSkpKSA9PSAxICl7CiAgcG9zLmxpbmtbW3doaWNoKGNvbC5zZWNvbmRhcnlbZyxdID09IG1pbihjb2wuc2Vjb25kYXJ5W2csXSkpIF1dID0gCiAgICBjKHBvcy5saW5rW1t3aGljaChjb2wuc2Vjb25kYXJ5W2csXSA9PSBtaW4oY29sLnNlY29uZGFyeVtnLF0pKSBdXSwgZykKICB9Cn0KIyAtLS0tCgoKcGNhXzEkaGlnaGxpZ2h0ID0gd2l0aChwY2FfMSwgCiAgICAgICAgICBpZmVsc2Uocm93bmFtZXMocGNhXzEpICVpbiUgcG9zLmxpbmskTDUsICJnZW5lcyByZWxhdGVkIHRvIEw1LzYiLAogICAgICAgICAgaWZlbHNlKHJvd25hbWVzKHBjYV8xKSAlaW4lIHBvcy5saW5rJEwyICwgImdlbmVzIHJlbGF0ZWQgdG8gTDIvMyIsCiAgICAgICAgICBpZmVsc2Uocm93bmFtZXMocGNhXzEpICVpbiUgcG9zLmxpbmskUCAsICJnZW5lcyByZWxhdGVkIHRvIFByb2ciICwKICAgICAgICAgIGlmZWxzZShyb3duYW1lcyhwY2FfMSkgJWluJSBwb3MubGluayRMMSAsICJnZW5lcyByZWxhdGVkIHRvIEwxIiAsCiAgICAgICAgICBpZmVsc2Uocm93bmFtZXMocGNhXzEpICVpbiUgcG9zLmxpbmskTDQgLCJnZW5lcyByZWxhdGVkIHRvIEw0IiAsCiAgICAgICJub3QgbWFya2VkIikpKSkpKQoKIyBCdXQgc29ydCB0aGVtIGJhc2VkIG9uIHRoZWlyIG9yZGVyIGluIGRlbmQ6CiNjb2xvcnNfdG9fdXNlIDwtIHBjYV8xJGhpZ2hsaWdodFtvcmRlci5kZW5kcm9ncmFtKGRlbmQpXQoKI215Y29sb3VycyA8LSBjKCJnZW5lcyByZWxhdGVkIHRvIEw1LzYiID0gIiMzQzU0ODhGRiIsImdlbmVzIHJlbGF0ZWQgdG8gTDIvMyI9IiNGMzlCN0ZGRiIsImdlbmVzIHJlbGF0ZWQgdG8gUHJvZyI9IiM0REJCRDVGRiIsImdlbmVzIHJlbGF0ZWQgdG8gTDEiPSIjRTY0QjM1RkYiLCJnZW5lcyByZWxhdGVkIHRvIEw0IiA9ICIjOTFEMUMyRkYiLCAibm90IG1hcmtlZCI9IiNCMDlDODVGRiIpCnBjYV8xJGhjbHVzdCA9IGN1dAoKcGNhXzEkY29sb3JzID0gTkEKcGNhXzFbcGNhXzEkaGlnaGxpZ2h0ID09ICJnZW5lcyByZWxhdGVkIHRvIEw1LzYiLCAiY29sb3JzIl0gPSAiIzNDNTQ4OEZGIgpwY2FfMVtwY2FfMSRoaWdobGlnaHQgPT0gImdlbmVzIHJlbGF0ZWQgdG8gTDIvMyIsImNvbG9ycyJdID0gIiNGMzlCN0ZGRiIKcGNhXzFbcGNhXzEkaGlnaGxpZ2h0ID09ICJnZW5lcyByZWxhdGVkIHRvIFByb2ciLCJjb2xvcnMiXSA9ICIjNERCQkQ1RkYiCnBjYV8xW3BjYV8xJGhpZ2hsaWdodCA9PSAiZ2VuZXMgcmVsYXRlZCB0byBMMSIsImNvbG9ycyJdID0gIiNFNjRCMzVGRiIKcGNhXzFbcGNhXzEkaGlnaGxpZ2h0ID09ICJnZW5lcyByZWxhdGVkIHRvIEw0IiwiY29sb3JzIl0gPSAiIzkxRDFDMkZGIgpwY2FfMVtwY2FfMSRoaWdobGlnaHQgPT0gIm5vdCBtYXJrZWQiLCJjb2xvcnMiXSA9ICIjQjA5Qzg1RkYiCgoKCgpkZW5kID1icmFuY2hlc19jb2xvcihkZW5kLGs9Nyxjb2w9YygiIzREQkJENUZGIiwiIzkxRDFDMkZGIiwiI0U2NEIzNUZGIiwiZ3JheTgwIiwiIzNDNTQ4OEZGIiwiI0YzOUI3RkZGIiwiZ3JheTgwIiApLGdyb3VwTGFiZWxzID0gVCkKZGVuZCA9Y29sb3JfbGFiZWxzKGRlbmQsaz03LGxhYmVscyA9IHJvd25hbWVzKHBjYV8xKSxjb2w9cGNhXzEkY29sb3JzKQoKCmRlbmQgJT4lCiAgZGVuZGV4dGVuZDo6c2V0KCJsYWJlbHMiLCBpZmVsc2UobGFiZWxzKGRlbmQpICVpbiUgcm93bmFtZXMocGNhXzEpW3Jvd25hbWVzKHBjYV8xKSAlaW4lIGNvbG5hbWVzKGcuc3BhY2UpXSAsbGFiZWxzKGRlbmQpLCIiKSkgJT4lCiAgIyAgc2V0KCJicmFuY2hlc19rX2NvbG9yIiwgdmFsdWUgPSBjKCJncmF5ODAiLCIjNERCQkQ1RkYiLCIjOTFEMUMyRkYiICwiZ3JheTgwIiwiI0YzOUI3RkZGIiwiI0U2NEIzNUZGIiwiIzNDNTQ4OEZGIiksIGsgPSA3KSAlPiUKIHBsb3QoaG9yaXo9RiwgYXhlcz1ULHlsaW0gPSBjKDAsODApKQpgYGAKYGBge3IgaW5jbHVkZT1GQUxTRX0KY2x1c3RlciA9IGN1dApjbHVzdGVyW2NsdXN0ZXIgPT0gMV0gPSAiIzREQkJENUZGIgpjbHVzdGVyW2NsdXN0ZXIgPT0gMl0gPSAiIzkxRDFDMkZGIgpjbHVzdGVyW2NsdXN0ZXIgPT0gM10gPSAgIiNFNjRCMzVGRiIKY2x1c3RlcltjbHVzdGVyID09IDRdID0gIiNCMDlDODVGRiIKY2x1c3RlcltjbHVzdGVyID09IDVdID0gIiMzQzU0ODhGRiIKY2x1c3RlcltjbHVzdGVyID09IDZdID0gIiNGMzlCN0ZGRiIKY2x1c3RlcltjbHVzdGVyID09IDddID0gIiNCMDlDODVGRiIKCgpwbG90Lm5ldygpCnBsb3QoZGVuZCxob3Jpej1ULCBheGVzPVQseGxpbSA9IGMoMTAwLDApLGxlYWZsYWIgPSAibm9uZSIpCmFibGluZSh2ID0gNDcsIGx0eSA9IDIpCmNvbG9yZWRfYmFycyhjbHVzdGVyLGRlbmQsaG9yaXogPSBULHNvcnRfYnlfbGFiZWxzX29yZGVyID0gRix5X3NoaWZ0ID0gMSwKICAgICAgICAgICAgICAgcm93TGFiZWxzPSAiIiApCmdyaWRHcmFwaGljczo6Z3JpZC5lY2hvKCkKdHJlZSA8LSBncmlkLmdyYWIoKQpgYGAKYGBge3IgZmlnLmhlaWdodD0xMCwgZmlnLndpZHRoPTd9CnBhcl9wY2EgPSBwY2FfMVtjb2xuYW1lcyhnLnNwYWNlKVtjb2xuYW1lcyhnLnNwYWNlKSAlaW4lIHJvd25hbWVzKHBjYV8xKV0sXQojcGxvdCBOIDEKcDEgPC0gZ2dwYXJhZ3JhcGgodGV4dCA9IHBhc3RlMChyb3duYW1lcyhwYXJfcGNhW3Bhcl9wY2EkaGNsdXN0ID09IHBhcl9wY2FbIkZlemYyIiwiaGNsdXN0Il0sXSksIGNvbGxhcHNlID0gIiwgIiksIAogICAgICAgICAgICAgICAgICBmYWNlID0gIml0YWxpYyIsIAogICAgICAgICAgICAgICAgICBzaXplID0xMCwgCiAgICAgICAgICAgICAgICAgIGNvbG9yID0gIiMzQzU0ODhGRiIpCgojcGxvdCBOIDIKcDIgPSBnZ3BhcmFncmFwaCh0ZXh0ID0gcGFzdGUwKHJvd25hbWVzKHBhcl9wY2FbcGFyX3BjYSRoY2x1c3QgPT0gdW5pcXVlKHBhcl9wY2EkaGNsdXN0KVshdW5pcXVlKHBhcl9wY2EkaGNsdXN0KSAlaW4lIHVuaXF1ZShwYXJfcGNhW3VubGlzdChsYXllcnMpLCJoY2x1c3QiXSldWzFdLF0pLCBjb2xsYXBzZSA9ICIsICIpLCAKICAgICAgICAgICAgICAgICBmYWNlID0gIml0YWxpYyIsIAogICAgICAgICAgICAgICAgIHNpemUgPTEwLCAKICAgICAgICAgICAgICAgICBjb2xvciA9ICJncmF5IikKCiNwbG90IE4gMwpwMyA9IGdncGFyYWdyYXBoKHRleHQgPSBwYXN0ZTAocm93bmFtZXMocGFyX3BjYVtwYXJfcGNhJGhjbHVzdCA9PSB1bmlxdWUocGFyX3BjYSRoY2x1c3QpWyF1bmlxdWUocGFyX3BjYSRoY2x1c3QpICVpbiUgdW5pcXVlKHBhcl9wY2FbdW5saXN0KGxheWVycyksImhjbHVzdCJdKV1bMl0sXSksIGNvbGxhcHNlID0gIiwgIiksIAogICAgICAgICAgICAgICAgIGZhY2UgPSAiaXRhbGljIiwgCiAgICAgICAgICAgICAgICAgc2l6ZSA9MTAsIAogICAgICAgICAgICAgICAgIGNvbG9yID0gImdyYXkiKQojcGxvdCBOIDQKcDQgPSBnZ3BhcmFncmFwaCh0ZXh0ID0gcGFzdGUwKHJvd25hbWVzKHBhcl9wY2FbcGFyX3BjYSRoY2x1c3QgPT0gcGFyX3BjYVsiUmVsbiIsImhjbHVzdCJdLF0pLCBjb2xsYXBzZSA9ICIsICIpLCAKICAgICAgICAgICAgICAgICBmYWNlID0gIml0YWxpYyIsIAogICAgICAgICAgICAgICAgIHNpemUgPTEwLCAKICAgICAgICAgICAgICAgICBjb2xvciA9ICIjRTY0QjM1RkYiKQoKI3Bsb3QgTiA1CnA1ID0gZ2dwYXJhZ3JhcGgodGV4dCA9IHBhc3RlMChyb3duYW1lcyhwYXJfcGNhW3Bhcl9wY2EkaGNsdXN0ID09IHBhcl9wY2FbIkN1eDEiLCJoY2x1c3QiXSxdKSwgY29sbGFwc2UgPSAiLCAiKSwgCiAgICAgICAgICAgICAgICAgZmFjZSA9ICJpdGFsaWMiLCAKICAgICAgICAgICAgICAgICBzaXplID0xMCwgCiAgICAgICAgICAgICAgICAgY29sb3IgPSBwYXJfcGNhWyJDdXgxIiwiY29sb3JzIl0pCiNwbG90IE4gNgpwNiA9IGdncGFyYWdyYXBoKHRleHQgPSBwYXN0ZTAocm93bmFtZXMocGFyX3BjYVtwYXJfcGNhJGhjbHVzdCA9PSBwYXJfcGNhWyJSb3JiIiwiaGNsdXN0Il0sXSksIGNvbGxhcHNlID0gIiwgIiksIAogICAgICAgICAgICAgICAgIGZhY2UgPSAiaXRhbGljIiwgCiAgICAgICAgICAgICAgICAgc2l6ZSA9MTAsIAogICAgICAgICAgICAgICAgIGNvbG9yID0gcGFyX3BjYVsiUm9yYiIsImNvbG9ycyJdKQojcGxvdCBOIDcKcDcgPSBnZ3BhcmFncmFwaCh0ZXh0ID0gcGFzdGUwKHJvd25hbWVzKHBhcl9wY2FbcGFyX3BjYSRoY2x1c3QgPT0gcGFyX3BjYVsiVmltIiwiaGNsdXN0Il0sXSksIGNvbGxhcHNlID0gIiwgIiksIAogICAgICAgICAgICAgICAgIGZhY2UgPSAiaXRhbGljIiwgCiAgICAgICAgICAgICAgICAgc2l6ZSA9MTAsIAogICAgICAgICAgICAgICAgIGNvbG9yID0gcGFyX3BjYVsiVmltIiwiY29sb3JzIl0pCgp3ID0gZ2dwYXJhZ3JhcGgodGV4dCA9ICIgIiwgCiAgICAgICAgICAgICAgICAgZmFjZSA9ICJpdGFsaWMiLCAKICAgICAgICAgICAgICAgICBzaXplID0xMCwgCiAgICAgICAgICAgICAgICAgY29sb3IgPSAid2hpdGUiKQoKcHAgPWdnYXJyYW5nZShwMyxwNSxwMSxwMixwNCxwNixwNyx3LAogICAgICAgICAgbmNvbCA9IDEsIG5yb3cgPSA4LAogICAgICAgICAgaGVpZ2h0cyA9IGMoMC4xLDAuMTUsMC4yMywgMC4xLCAwLjIsIDAuMiwgMC4xLCAwLjM1KSkKCgogICAgCmxheSA8LSByYmluZChjKDEsTkEpLAogICAgICAgICAgICAgYygxLDIuNSksCiAgICAgICAgICAgICBjKDEsMi41KSwKICAgICAgICAgICAgIGMoMSwyLjUpLAogICAgICAgICAgICAgYygxLDIuNSksCiAgICAgICAgICAgICBjKDEsMi41KSwKICAgICAgICAgICAgIGMoMSxOQSkpCgpncmlkRXh0cmE6OmdyaWQuYXJyYW5nZSh0cmVlLCBwcCwgbGF5b3V0X21hdHJpeCA9IGxheSkKCmBgYAoKb3IganVzdCB3aXRoIHByaW1hcnkgbWFya2VycwoKYGBge3IgZmlnLndpZHRoPSAxMH0KIyBzb21lIG1vcmUgZ2VuZXMgYXMgbGFuZG1hcmtzCmNvbnRyb2xzID1saXN0KCJnZW5lcyByZWxhdGVkIHRvIEw1LzYiPWMoIkZveHAyIiwiVGJyMSIpLCAiZ2VuZXMgcmVsYXRlZCB0byBMMi8zIj1jKCJNZWYyYyIpLCAiZ2VuZXMgcmVsYXRlZCB0byBQcm9nIj1jKCJOZXMiLCJTb3gyIikgLCAiZ2VuZXMgcmVsYXRlZCB0byBMMSI9YygpICwgImdlbmVzIHJlbGF0ZWQgdG8gTDQiPWMoKSkgCmRlbmQgJT4lCmRlbmRleHRlbmQ6OnNldCgibGFiZWxzIiwgaWZlbHNlKGxhYmVscyhkZW5kKSAlaW4lIHJvd25hbWVzKHBjYV8xKVtyb3duYW1lcyhwY2FfMSkgJWluJSBjKHVubGlzdChsYXllcnMpLHVubGlzdChjb250cm9scykpXSwgbGFiZWxzKGRlbmQpLCAiIikpICU+JQogIGRlbmRleHRlbmQ6OnNldCgiYnJhbmNoZXNfa19jb2xvciIsIHZhbHVlID0gYygiZ3JheTgwIiwiIzREQkJENUZGIiwiIzkxRDFDMkZGIiAsImdyYXk4MCIsIiNGMzlCN0ZGRiIsIiNFNjRCMzVGRiIsIiMzQzU0ODhGRiIpLCBrID0gNykgJT4lCnBsb3QoaG9yaXo9RiwgYXhlcz1ULHlsaW0gPSBjKDAsMTAwKSkKCmBgYAoKCgoKTm93IHdlIGNhbiBwbG90IHRoZSBQQ0EKCmBgYHtyfQojIGRhdGFmcmFtZSB0byBiZSBhYmxlIHRvIGxhYmVsIG9ubHkgcHJpbWFyeSBtYXJrZXJzIGFuZCBjb250cm9sIGdlbmVzCnRleHRkZiA8LSBwY2FfMVtyb3duYW1lcyhwY2FfMSkgJWluJSBjKHVubGlzdChsYXllcnMpLHVubGlzdChjb250cm9scykpICwgXQoKIGZvciAobSBpbiBjKDE6bGVuZ3RoKGNvbnRyb2xzKSkpIHsKICBmb3IgKGcgaW4gY29udHJvbHNbW21dXSkgewogICAgaWYoZyAlaW4lIHJvd25hbWVzKHRleHRkZikpewogICAgICB0ZXh0ZGZbZywiaGlnaGxpZ2h0Il0gPSBuYW1lcyhjb250cm9sc1ttXSkKICAgIH0gCiAgfQp9CgojIGRlY2lkaW5nIHRoZSBjb2xvcnMKbXljb2xvdXJzIDwtIGMoImdlbmVzIHJlbGF0ZWQgdG8gTDUvNiIgPSAiIzNDNTQ4OEZGIiwiZ2VuZXMgcmVsYXRlZCB0byBMMi8zIj0iI0YzOUI3RkZGIiwiZ2VuZXMgcmVsYXRlZCB0byBQcm9nIj0iIzREQkJENUZGIiwiZ2VuZXMgcmVsYXRlZCB0byBMMSI9IiNFNjRCMzVGRiIsImdlbmVzIHJlbGF0ZWQgdG8gTDQiID0gIiM5MUQxQzJGRiIsICJub3QgbWFya2VkIj0iI0IwOUM4NUZGIikKCiMgdG8gYXNzaW5nIGNvcnJlY2x5IHRoZSBjbHVzdGVyIG51bWJlciBhbmQgdGhlIGNvbG9yCm15Y29sb3VyczIgPSBjKCJSZWxuIiwiU2F0YjIiLCJSb3JiIiwiQmNsMTFiIiwiVmltIikKbmFtZXMobXljb2xvdXJzMikgPSB1bmlxdWUoY3V0W3VubGlzdChsYXllcnMpXSkKCm15Y29sb3VyczJbbXljb2xvdXJzMiA9PSAiUmVsbiJdID0gIiNFNjRCMzVGRiIKbXljb2xvdXJzMltteWNvbG91cnMyID09ICJTYXRiMiJdID0gIiNGMzlCN0ZGRiIKbXljb2xvdXJzMltteWNvbG91cnMyID09ICJSb3JiIl0gPSAiIzkxRDFDMkZGIgpteWNvbG91cnMyW215Y29sb3VyczIgPT0gIkJjbDExYiJdID0gIiMzQzU0ODhGRiIKbXljb2xvdXJzMltteWNvbG91cnMyID09ICJWaW0iXSA9ICIjNERCQkQ1RkYiCmNvbG9yX3RvX2FkZCA9IHVuaXF1ZShwY2FfMSRoY2x1c3QpWyF1bmlxdWUocGNhXzEkaGNsdXN0KSAlaW4lIGFzLm51bWVyaWMobmFtZXMobXljb2xvdXJzMikpXQpuYW1lcyhjb2xvcl90b19hZGQpID0gdW5pcXVlKHBjYV8xJGhjbHVzdClbIXVuaXF1ZShwY2FfMSRoY2x1c3QpICVpbiUgYXMubnVtZXJpYyhuYW1lcyhteWNvbG91cnMyKSldCmNvbG9yX3RvX2FkZFtjb2xvcl90b19hZGQgJWluJSAKICAgICAgICAgICAgICAgICB1bmlxdWUocGNhXzEkaGNsdXN0KVshdW5pcXVlKHBjYV8xJGhjbHVzdCkgJWluJSBhcy5udW1lcmljKG5hbWVzKG15Y29sb3VyczIpKV1dID0gIiNCMDlDODVGRiIKbXljb2xvdXJzMiA9IGMobXljb2xvdXJzMixjb2xvcl90b19hZGQpCgpwY2ExID0gZ2dwbG90KHN1YnNldChwY2FfMSwhaGNsdXN0ICVpbiUgdW5pcXVlKGN1dFt1bmxpc3QobGF5ZXJzKV0pICApLCBhZXMoeD1QQzEsIHk9UEMyKSkgKyAgZ2VvbV9wb2ludChhbHBoYSA9IDAuMyxjb2xvciA9ICIjQjA5Qzg1RkYiLHNpemU9MSkKCnBjYV8xJG5hbWVzID0gcm93bmFtZXMocGNhXzEpCiNwY2EyID0gcGNhMSArIGdlb21fcG9pbnQoZGF0YSA9IHN1YnNldChwY2FfMSwgaGlnaGxpZ2h0ICE9ICJub3QgbWFya2VkIiApLCBhZXMoeD1QQzEsIHk9UEMyLCBjb2xvdXI9aGNsdXN0KSxzaXplPTIuNSxhbHBoYSA9IDAuOSkgCnBjYTIgPSBwY2ExICsgZ2VvbV9wb2ludChkYXRhID0gc3Vic2V0KHBjYV8xLCBoY2x1c3QgJWluJSB1bmlxdWUoY3V0W3VubGlzdChsYXllcnMpXSkgKSwgYWVzKHg9UEMxLCB5PVBDMiwgY29sb3VyPWFzLmNoYXJhY3RlcihoY2x1c3QpKSxzaXplPTEsYWxwaGEgPSAwLjUpICsgCiBzY2FsZV9jb2xvcl9tYW51YWwoICJTdGF0dXMiLCB2YWx1ZXMgPSBteWNvbG91cnMyKSAgKwogIHNjYWxlX2ZpbGxfbWFudWFsKCAiU3RhdHVzIiwgdmFsdWVzID0gbXljb2xvdXJzMikgICsKICB4bGFiKCIiKSArIHlsYWIoIiIpICsKICBnZW9tX2xhYmVsX3JlcGVsKGRhdGEgPXRleHRkZiAsIGFlcyh4ID0gUEMxLCB5ID0gUEMyLCBsYWJlbCA9IHJvd25hbWVzKHRleHRkZiksZmlsbD1hcy5jaGFyYWN0ZXIoaGNsdXN0KSksCiAgICAgICAgICAgICAgICAgICBsYWJlbC5zaXplID0gTkEsIAogICAgICAgICAgICAgICAgICAgYWxwaGEgPSAwLjUsIAogICAgICAgICAgICAgICAgICAgZGlyZWN0aW9uID0gImJvdGgiLAogICAgICAgICAgICAgICAgICAgbmEucm09VFJVRSwKICAgICAgICAgICAgICAgICAgIHNlZWQgPSAxMjM0KSArCiAgZ2VvbV9sYWJlbF9yZXBlbChkYXRhID10ZXh0ZGYgLCBhZXMoeCA9IFBDMSwgeSA9IFBDMiwgbGFiZWwgPSByb3duYW1lcyh0ZXh0ZGYpKSwKICAgICAgICAgICAgICAgICAgIGxhYmVsLnNpemUgPSBOQSwgCiAgICAgICAgICAgICAgICAgICBzZWdtZW50LmNvbG9yID0gJ2JsYWNrJywKICAgICAgICAgICAgICAgICAgIHNlZ21lbnQuc2l6ZSA9IDAuNSwKICAgICAgICAgICAgICAgICAgIGRpcmVjdGlvbiA9ICJib3RoIiwKICAgICAgICAgICAgICAgICAgIGFscGhhID0gMSwgCiAgICAgICAgICAgICAgICAgICBuYS5ybT1UUlVFLAogICAgICAgICAgICAgICAgICAgZmlsbCA9IE5BLAogICAgICAgICAgICAgICAgICAgc2VlZCA9IDEyMzQpICsKICBnZ3RpdGxlKCJQQ0EiKSArCiAgdGhlbWVfbGlnaHQoYmFzZV9zaXplPTEwKSArCiAgICB0aGVtZShheGlzLnRleHQueD1lbGVtZW50X2JsYW5rKCkscGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplPTE0LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmFjZT0iaXRhbGljIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG9yPSIjM0M1NDg4RkYiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBoanVzdD0wLjAxLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsaW5laGVpZ2h0PTEuMixtYXJnaW4gPSBtYXJnaW4odCA9IDUsIGIgPSAtMTUpKSwKICAgICAgICBheGlzLnRleHQueT1lbGVtZW50X2JsYW5rKCksCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSAgIyB0aXRsKQoKcGNhMiAjKyBnZW9tX2VuY2lyY2xlKGRhdGEgPSBwY2FfMSwgYWVzKGdyb3VwPWhjbHVzdCkpIApgYGAKCgpgYGB7ciB9CnNldC5zZWVkKE5VTEwpCmNlbGwgPSBzYW1wbGUobmNvbChvYmpFMTdAcmF3KSwxLHJlcGxhY2UgPSBUKQpwcmludChjZWxsKQpnZW5lcy50by5jb2xvci5yZWQgPSB3aGljaChvYmpFMTdAcmF3WyxjZWxsXSA+IDApCmxlbmd0aChnZW5lcy50by5jb2xvci5yZWQpCgpwY2EzID0gcGNhMiArIGdlb21fcG9pbnQoZGF0YSA9IHN1YnNldChwY2FfMSwgbmFtZXMgJWluJSBuYW1lcyhnZW5lcy50by5jb2xvci5yZWQpKSwgY29sb3I9InJlZCIpCgpwY2EzCmBgYAoKCgp0LVNORSBjb2RlIGFuZCBwbG90CgpgYGB7cn0KIyBydW4gdGhlIHQtU05FCmNsLmdlbmVzLnRzbmUgPSBSdHNuZShnLnNwYWNlICxpbml0aWFsX2RpbXMgPSAxMDAsIGRpbXMgPSAyLCBwZXJwbGV4aXR5PTMwLGV0YSA9IDIwMCwgdmVyYm9zZT1GLCBtYXhfaXRlciA9IDMwMDAsdGhldGE9MC40LG51bV90aHJlYWRzID0gMTAscGNhX2NlbnRlciA9IFQsIHBjYV9zY2FsZSA9IEZBTFNFLCBub3JtYWxpemUgPSBUICkKCmRfdHNuZV8xID0gYXMuZGF0YS5mcmFtZShjbC5nZW5lcy50c25lJFkpCnJvd25hbWVzKGRfdHNuZV8xKSA9IHJvd25hbWVzKGcuc3BhY2UpCgpkX3RzbmVfMSA9IGRfdHNuZV8xW29yZGVyLmRlbmRyb2dyYW0oZGVuZCksXQoKIyBzYXZlIHRoZSBjbHVzdGVyIG51bWViciBpbnNpZGUgYSBkYXRhZnJhbWUgd2l0aCB0aGUgdC1TTkUgaW5mb3JtYXRpb24KZF90c25lXzEkaGNsdXN0ID0gY3V0CgpkX3RzbmVfMSRuYW1lcyA9IHJvd25hbWVzKGRfdHNuZV8xKQoKIyBhcyBiZWZvcmUgdG8gbGFiZWwgb25seSBzb21lIGdlbmVzCnRleHRkZiA8LSBkX3RzbmVfMVtyb3duYW1lcyhkX3RzbmVfMSkgJWluJSBjKHVubGlzdChsYXllcnMpLHVubGlzdChjb250cm9scykpLF0KCmZvciAobSBpbiBjKDE6bGVuZ3RoKGNvbnRyb2xzKSkpIHsKICBmb3IgKGcgaW4gY29udHJvbHNbW21dXSkgewogICAgaWYoZyAlaW4lIHJvd25hbWVzKHRleHRkZikpewogICAgICB0ZXh0ZGZbZywiaGlnaGxpZ2h0Il0gPSBuYW1lcyhjb250cm9sc1ttXSkKICAgIH0gCiAgfQp9CgoKIHAxID0gZ2dwbG90KHN1YnNldChkX3RzbmVfMSwhaGNsdXN0ICVpbiUgdW5pcXVlKGN1dFt1bmxpc3QobGF5ZXJzKV0pKSwgYWVzKHg9VjEsIHk9VjIpKSArICBnZW9tX3BvaW50KGFscGhhID0gMC4zLCBjb2xvciA9ICIjQjA5Qzg1RkYiLCBzaXplPTEpCgpwMiA9IHAxICsgZ2VvbV9wb2ludChkYXRhID0gc3Vic2V0KGRfdHNuZV8xLCBoY2x1c3QgJWluJSB1bmlxdWUoY3V0W3VubGlzdChsYXllcnMpXSkgKSwgYWVzKHg9VjEsIHk9VjIsIGNvbG91cj1hcy5jaGFyYWN0ZXIoaGNsdXN0KSksc2l6ZT0xLGFscGhhID0gMC41KSArCiAgICBzY2FsZV9jb2xvcl9tYW51YWwoIlN0YXR1cyIsIHZhbHVlcyA9IG15Y29sb3VyczIpICArCiAgc2NhbGVfZmlsbF9tYW51YWwoIlN0YXR1cyIsIHZhbHVlcyA9IG15Y29sb3VyczIpICArCiAgeGxhYigiIikgKyB5bGFiKCIiKSsKICBnZW9tX2xhYmVsX3JlcGVsKGRhdGEgPXRleHRkZiAsIGFlcyh4ID0gVjEsIHkgPSBWMiwgbGFiZWwgPSBuYW1lcyxmaWxsPWFzLmNoYXJhY3RlcihoY2x1c3QpKSwKICAgICAgICAgICAgICAgICAgIGxhYmVsLnNpemUgPSBOQSwgCiAgICAgICAgICAgICAgICAgICBhbHBoYSA9IDAuNSwgCiAgICAgICAgICAgICAgICAgICBkaXJlY3Rpb24gPSAiYm90aCIsCiAgICAgICAgICAgICAgICAgICBuYS5ybT1UUlVFLAogICAgICAgICAgICAgICAgICAgc2VlZCA9IDEyMzQpICsKICBnZW9tX2xhYmVsX3JlcGVsKGRhdGEgPXRleHRkZiAsIGFlcyh4ID0gVjEsIHkgPSBWMiwgbGFiZWwgPSBuYW1lcyksCiAgICAgICAgICAgICAgICAgICBsYWJlbC5zaXplID0gTkEsIAogICAgICAgICAgICAgICAgICAgc2VnbWVudC5jb2xvciA9ICdibGFjaycsCiAgICAgICAgICAgICAgICAgICBzZWdtZW50LnNpemUgPSAwLjUsCiAgICAgICAgICAgICAgICAgICBkaXJlY3Rpb24gPSAiYm90aCIsCiAgICAgICAgICAgICAgICAgICBhbHBoYSA9IDEsIAogICAgICAgICAgICAgICAgICAgbmEucm09VFJVRSwKICAgICAgICAgICAgICAgICAgIGZpbGwgPSBOQSwKICAgICAgICAgICAgICAgICAgIHNlZWQgPSAxMjM0KSArCiAgZ2d0aXRsZSgidC1TTkUiKSArCiAgdGhlbWVfbGlnaHQoYmFzZV9zaXplPTEwKSArCiAgdGhlbWUoYXhpcy50ZXh0Lng9ZWxlbWVudF9ibGFuaygpLHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZT0xNCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZhY2U9Iml0YWxpYyIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvcj0iIzNDNTQ4OEZGIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaGp1c3Q9MC4wMSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGluZWhlaWdodD0xLjIsbWFyZ2luID0gbWFyZ2luKHQgPSA1LCBiID0gLTE1KSksCiAgICAgICAgYXhpcy50ZXh0Lnk9ZWxlbWVudF9ibGFuaygpLAogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikgICMgdGl0bCkKcDIKYGBgCkNvZGUgdG8gY3JlYXRlIGFuIGl0ZXJhY3RpdmUgcGxvdC4gVGhpcyBjYW4gYmUgbW9kaWZpZWQgdG8gYmUgdXNlZCB3aXRoIGFsbCB0aGUgcGxvdHMuCgpgYGB7ciBlY2hvPVRSVUV9CgpwID0gZ2dwbG90KGRfdHNuZV8xLCBhZXMoeD1WMSwgeT1WMiwgdGV4dD0gcGFzdGUoImdlbmU6ICIsbmFtZXMpKSkgKyAgCiAgZ2VvbV9wb2ludChzaXplPTIsIGFlcyhjb2xvdXI9YXMuY2hhcmFjdGVyKGhjbHVzdCkpLCBhbHBoYT0wLjgpICsKICBzY2FsZV9jb2xvcl9tYW51YWwoIlN0YXR1cyIsIHZhbHVlcyA9IG15Y29sb3VyczIpICArCiAgeGxhYigiIikgKyB5bGFiKCIiKSArCiAgZ2d0aXRsZSgidC1TTkUiKSArCiAgdGhlbWVfbGlnaHQoYmFzZV9zaXplPTEwKSArCiAgdGhlbWUoYXhpcy50ZXh0Lng9ZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGV4dC55PWVsZW1lbnRfYmxhbmsoKSkKCmdncGxvdGx5KHApCmBgYAoKTXVsdGlkaW1lbnNpb25hbCBzY2FsaW5nIChNRFMpIGFuZCBwbG90CmBgYHtyfQojIHJ1biB0aGUgTURTCmdlbmVzLmRpc3QuZXVjID0gIGRpc3QoZy5zcGFjZSwgbWV0aG9kID0gICJldWNsaWRlYW4iKQojZml0IDwtIGlzb01EUyhnZW5lcy5kaXN0LmV1YykgIyBub3QgbGluZWFyCmZpdCA8LSBpc29NRFMoZ2VuZXMuZGlzdC5ldWMpCgpmaXQuZ2VuZXMgPSBhcy5kYXRhLmZyYW1lKGZpdCRwb2ludHMpCgpmaXQuZ2VuZXMgPSBmaXQuZ2VuZXNbb3JkZXIuZGVuZHJvZ3JhbShkZW5kKSxdCgpmaXQuZ2VuZXMkaGNsdXN0ID0gY3V0CgoKZml0LmdlbmVzJG5hbWVzID0gcm93bmFtZXMoZml0LmdlbmVzKQoKbXljb2xvdXJzMyA8LSBjKCJjbHVzdGVyIEw1LzYgbWFya2VycyIgPSAiIzNDNTQ4OEZGIiwiY2x1c3RlciBMMi8zIG1hcmtlcnMiPSIjRjM5QjdGRkYiLCJjbHVzdGVyIFByb2cgbWFya2VycyI9IiM0REJCRDVGRiIsImNsdXN0ZXIgTDEgbWFya2VycyI9IiNFNjRCMzVGRiIsImNsdXN0ZXIgTDQgbWFya2VycyIgPSAiIzkxRDFDMkZGIiwgIm5vdCBpZGVudGlmaWVkIGNsdXN0ZXIiPSIjQjA5Qzg1RkYiKQoKI215Y29sb3VyczMgPC0gYygiY2x1c3RlciBsYXllciBWLVZJIG1hcmtlcnMiID0gIiMzQzU0ODhGRiIsImNsdXN0ZXIgbGF5ZXIgSUktSUlJIG1hcmtlcnMiPSIjRjM5QjdGRkYiLCJjbHVzdGVyIHByb2dlbml0b3IgbWFya2VycyI9IiM0REJCRDVGRiIsImNsdXN0ZXIgbGF5ZXIgSSBtYXJrZXJzIj0iI0U2NEIzNUZGIiwiY2x1c3RlciBsYXllciBJViBtYXJrZXJzIiA9ICIjOTFEMUMyRkYiLCAibm90IGlkZW50aWZpZWQgY2x1c3RlciI9IiNCMDlDODVGRiIpCgoKI2ZpdC5nZW5lcyRoY2x1c3QgPSBmYWN0b3IoY3V0cmVlKGhjLm5vcm0sIDcpKQp1c2VkID0gdmVjdG9yKCkKZm9yIChrIGluIGMoMTpsZW5ndGgobGF5ZXJzKSkpIHsKICAjcHJpbnQoaykKICB0dCA9YXMubnVtZXJpYyhjdXRbbGF5ZXJzW1trXV1dWzFdKQogIGZpdC5nZW5lc1tmaXQuZ2VuZXMkaGNsdXN0ID09IHR0LCJjbHVzdGVyIl0gPSBwYXN0ZSgiY2x1c3RlciIsbmFtZXMobGF5ZXJzW2tdKSwibWFya2VycyIsIHNlcCA9ICIgIiApCiAgdXNlZCA9IGModXNlZCxjdXRbbGF5ZXJzW1trXV1dWzFdKQp9CgpmaXQuZ2VuZXNbZml0LmdlbmVzJGhjbHVzdCAlaW4lICh1bmlxdWUoZml0LmdlbmVzJGhjbHVzdClbIXVuaXF1ZShmaXQuZ2VuZXMkaGNsdXN0KSAlaW4lIHVzZWRdKSxdJGNsdXN0ZXIgPSAibm90IGlkZW50aWZpZWQgY2x1c3RlciIKCnRleHRkZiA8LSBmaXQuZ2VuZXNbcm93bmFtZXMoZml0LmdlbmVzKSAlaW4lIGModW5saXN0KGxheWVycyksdW5saXN0KGNvbnRyb2xzKSksXQoKICAgZjEgPSBnZ3Bsb3Qoc3Vic2V0KGZpdC5nZW5lcywhaGNsdXN0ICVpbiUgdW5pcXVlKGN1dFt1bmxpc3QobGF5ZXJzKV0pICksIGFlcyh4PVYxLCB5PVYyKSkgKyAgZ2VvbV9wb2ludChhbHBoYSA9IDAuMywgY29sb3IgPSAiI0IwOUM4NUZGIiwgc2l6ZT0xKQoKZjIgPSBmMSArIGdlb21fcG9pbnQoZGF0YSA9IHN1YnNldChmaXQuZ2VuZXMsIGhjbHVzdCAlaW4lIHVuaXF1ZShjdXRbdW5saXN0KGxheWVycyldKSApLCAKICAgICAgICAgICAgICAgICAgICAgYWVzKHg9VjEsIHk9VjIsIGNvbG91cj1jbHVzdGVyKSwgc2l6ZT0xLGFscGhhID0gMC41KSArCiAgc2NhbGVfY29sb3JfbWFudWFsKCJTdGF0dXMiLCB2YWx1ZXMgPSBteWNvbG91cnMzLAogICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBjKCJMYXllciBJIGNsdXN0ZXIgIiwiTGF5ZXJzIElJL0lJSSBjbHVzdGVyIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiTGF5ZXIgSVYgY2x1c3RlciIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkxheWVycyBWL1ZJIGNsdXN0ZXIiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJQcm9nZW5pdG9ycyBjbHVzdGVyIikgKSAgKwogIHNjYWxlX2ZpbGxfbWFudWFsKCJTdGF0dXMiLCB2YWx1ZXMgPSBteWNvbG91cnMzKSAgKyAKICB4bGFiKCIiKSArIHlsYWIoIiIpKwogIGdlb21fbGFiZWxfcmVwZWwoZGF0YSA9dGV4dGRmICwgYWVzKHggPSBWMSwgeSA9IFYyLCBsYWJlbCA9IHJvd25hbWVzKHRleHRkZiksZmlsbD1jbHVzdGVyKSwKICAgICAgICAgICAgICAgICAgIGxhYmVsLnNpemUgPSBOQSwgCiAgICAgICAgICAgICAgICAgICBhbHBoYSA9IDAuNSwgCiAgICAgICAgICAgICAgICAgICBkaXJlY3Rpb24gPSJib3RoIiwKICAgICAgICAgICAgICAgICAgIG5hLnJtPVRSVUUsCiAgICAgICAgICAgICAgICAgICBzZWVkID0gMTIzNCwgc2hvdy5sZWdlbmQgPSBGQUxTRSkgKwogIGdlb21fbGFiZWxfcmVwZWwoZGF0YSA9dGV4dGRmICwgYWVzKHggPSBWMSwgeSA9IFYyLCBsYWJlbCA9IHJvd25hbWVzKHRleHRkZikpLAogICAgICAgICAgICAgICAgICAgbGFiZWwuc2l6ZSA9IE5BLCAKICAgICAgICAgICAgICAgICAgIHNlZ21lbnQuY29sb3IgPSAnYmxhY2snLAogICAgICAgICAgICAgICAgICAgc2VnbWVudC5zaXplID0gMC41LAogICAgICAgICAgICAgICAgICAgZGlyZWN0aW9uID0gImJvdGgiLAogICAgICAgICAgICAgICAgICAgYWxwaGEgPSAxLCAKICAgICAgICAgICAgICAgICAgIG5hLnJtPVRSVUUsCiAgICAgICAgICAgICAgICAgICBmaWxsID0gTkEsCiAgICAgICAgICAgICAgICAgICBzZWVkID0gMTIzNCwgc2hvdy5sZWdlbmQgPSBGQUxTRSkgKwogIGdndGl0bGUoIk1EUyIpICsKICB0aGVtZV9saWdodChiYXNlX3NpemU9MTApICsKICB0aGVtZShheGlzLnRleHQueD1lbGVtZW50X2JsYW5rKCkscGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplPTE0LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmFjZT0iaXRhbGljIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG9yPSIjM0M1NDg4RkYiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBoanVzdD0wLjAxLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsaW5laGVpZ2h0PTEuMixtYXJnaW4gPSBtYXJnaW4odCA9IDUsIGIgPSAtMTUpKSwKICAgICAgICBheGlzLnRleHQueT1lbGVtZW50X2JsYW5rKCksCiAgICAgICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KGNvbG9yID0gIiMzQzU0ODhGRiIsZmFjZSA9Iml0YWxpYyIgKSwKICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIikgICMgdGl0bCkKCgpmMiArIHNjYWxlX3lfcmV2ZXJzZSgpKyBzY2FsZV94X3JldmVyc2UoKSMrIGdlb21fZW5jaXJjbGUoZGF0YSA9IGZpdC5nZW5lcywgYWVzKGdyb3VwPWA1X2NsdXN0ZXJzYCkpIApgYGAKYGBge3IgZXZhbD1GQUxTRSwgaW5jbHVkZT1GQUxTRX0KbGlicmFyeSgiQW5ub3RhdGlvbkRiaSIpCmxpYnJhcnkoIm9yZy5NbS5lZy5kYiIpCmxpYnJhcnkoIkdPLmRiIikKCmBgYApgYGB7ciBldmFsPUZBTFNFLCBpbmNsdWRlPUZBTFNFfQpHTyA9ICJHTzowMDAzNjc2IiAjbnVjbGVpYyBhY2lkIGJpbmRpbmcKbGlicmFyeShvcmcuTW0uZWcuZGIpCmxpc3QgPSBzZWxlY3Qob3JnLk1tLmVnLmRiLCBrZXlzID0gcm93bmFtZXMocGNhXzEpLAogICAgICAgICAgICAgIGNvbHVtbnM9YygiU1lNQk9MIiwiR09BTEwiKSxrZXl0eXBlPSJTWU1CT0wiKSAjW2ZpdC5nZW5lcyRoY2x1c3QgJWluJSBjKDcsNCwxLDIsMyksXSksCmxpc3QgPSBsaXN0W2xpc3QkR09BTEwgPT0gR08sXQpsaXN0ID0gbGlzdFtjb21wbGV0ZS5jYXNlcyhsaXN0KSxdCm5vdC51c2VmdWwgPSBjKCJOQVMiLCJUQVMiLCJJRUEiLCJJQyIsIk5EIikKbGlzdDEgPSBsaXN0WyFsaXN0JEVWSURFTkNFQUxMICVpbiUgbm90LnVzZWZ1bCxdCmxpc3QxID0gdW5pcXVlKGxpc3QxJFNZTUJPTCkKcGNhXzEkR08gPSBOQQpwY2FfMVtsaXN0MSxdJEdPID0gIm51Y2xlaWMgYWNpZCBiaW5kaW5nIgpwY2FfMVtsaXN0MSxjKDExOm5jb2wocGNhXzEpKV0KYGBgCmBgYHtyfQpzZXNzaW9uSW5mbygpCmBgYAoK